package com.orange.base.core.config;

import java.util.ArrayList;
import java.util.List;
import java.util.Properties;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.filter.logging.Log4j2Filter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;

@Configuration
@EnableConfigurationProperties({ DruidDataSourceProperties.class })
@PropertySource(value = "classpath:druid.properties")
public class DruidConfiguration {

    @Value("${spring.datasource.druid.dbType}")
    private String dbType;

    @Value("${spring.datasource.druid.url:#{null}}")
    private String url;

    @Autowired
    private DruidDataSourceProperties properties;

    @Bean(destroyMethod = "close", initMethod = "init")
    @ConfigurationProperties(prefix = "spring.datasource.druid")
    public DataSource druidDataSource() {
        getH2DefaultUrl();
        DruidDataSource druidDataSource = new DruidDataSource();
        if ("h2".equals(dbType) && url == null) {
            druidDataSource.setUrl(getH2DefaultUrl());
        }
        druidDataSource.setDbType(properties.getDbType());
        druidDataSource.setInitialSize(properties.getInitialSize());
        druidDataSource.setMinIdle(properties.getMinIdle());
        druidDataSource.setMaxActive(properties.getMaxActive());
        druidDataSource.setMaxWait(properties.getMaxWait());
        druidDataSource.setTimeBetweenEvictionRunsMillis(properties.getTimeBetweenEvictionRunsMillis());
        druidDataSource.setMinEvictableIdleTimeMillis(properties.getMinEvictableIdleTimeMillis());
        druidDataSource.setValidationQuery(properties.getValidationQuery());
        druidDataSource.setTestWhileIdle(properties.isTestWhileIdle());
        druidDataSource.setTestOnBorrow(properties.isTestOnBorrow());
        druidDataSource.setTestOnReturn(properties.isTestOnReturn());
        druidDataSource.setPoolPreparedStatements(properties.isPoolPreparedStatements());
        druidDataSource.setMaxPoolPreparedStatementPerConnectionSize(properties.getMaxPoolPreparedStatementPerConnectionSize());

        // 查询表的时候显示注释信息
        Properties connectionProperties = new Properties();
        connectionProperties.setProperty("remarks", "true");
        if ("mysql".equalsIgnoreCase(dbType)) {
            connectionProperties.setProperty("useInformationSchema", "true");
        }
        druidDataSource.setConnectProperties(connectionProperties);

        List<Filter> filters = new ArrayList<Filter>();
        Log4j2Filter log4j2Filter = getLog4j2Filter();
        filters.add(log4j2Filter);
        WallFilter wallFilter = getWallFilter();
        filters.add(wallFilter);
        druidDataSource.setProxyFilters(filters);
        return druidDataSource;
    }

    private String getH2DefaultUrl() {
        String rootPath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
        String url = "jdbc:h2:file:" + rootPath + "/orange;AUTO_SERVER=TRUE";
        return url;
    }

    @Bean
    public ServletRegistrationBean<StatViewServlet> druidStatViewServlet() {
        // org.springframework.boot.context.embedded.ServletRegistrationBean提供类的进行注册.
        ServletRegistrationBean<StatViewServlet> servletRegistrationBean = new ServletRegistrationBean<StatViewServlet>(new StatViewServlet(),
                "/druid/*");
        return servletRegistrationBean;
    }

    @Bean
    public FilterRegistrationBean<WebStatFilter> druidStatFilter() {
        FilterRegistrationBean<WebStatFilter> filterRegistrationBean = new FilterRegistrationBean<WebStatFilter>(new WebStatFilter());
        // 添加过滤规则.
        filterRegistrationBean.addUrlPatterns("/*");
        // 添加不需要忽略的格式信息.
        String exclusions = "*.html,*.js,*.css,*.gif,*.icon,*.ico,*.png,*.jpg,*.jpeg,*.eot,*.svg,*.ttf,*.woff,*.woff2,*.swf,/druid/*";
        filterRegistrationBean.addInitParameter("exclusions", exclusions);
        return filterRegistrationBean;
    }

    private Log4j2Filter getLog4j2Filter() {
        Log4j2Filter log4j2Filter = new Log4j2Filter();
        log4j2Filter.setConnectionLogEnabled(true);
        log4j2Filter.setStatementLogEnabled(true);
        log4j2Filter.setResultSetLogEnabled(false);
        log4j2Filter.setStatementExecutableSqlLogEnable(true);
        return log4j2Filter;
    }

    private WallFilter getWallFilter() {
        WallConfig wallConfig = new WallConfig();
        if ("oracle".equalsIgnoreCase(dbType)) {
            wallConfig.setDir("META-INF/druid/wall/oracle");
        } else if ("mysql".toString().equalsIgnoreCase(dbType)) {
            wallConfig.setDir("META-INF/druid/wall/mysql");
        }
        wallConfig.setMultiStatementAllow(true);
        // 检查SELECT语句的WHERE子句是否是一个永真条件 false为不校验
        wallConfig.setSelectWhereAlwayTrueCheck(false);
        // 检查查询条件(WHERE/HAVING子句)中是否包含AND永真条件 true为允许
        wallConfig.setConditionAndAlwayTrueAllow(true);
        // 检查查询条件(WHERE/HAVING子句)中是否包含AND永假条件 true为允许
        wallConfig.setConditionAndAlwayFalseAllow(true);
        WallFilter wallFilter = new WallFilter();
        wallFilter.setConfig(wallConfig);
        return wallFilter;
    }

}
